package mviewer.types;

public class Vector3f implements IVector {
	
	private float x, y, z;

	public Vector3f() {
		this(0f, 0f, 0f);
	}

	public Vector3f(Vector3f v) {
		this(v.x, v.y, v.z);
	}

	public Vector3f(float f) {
		this(f, f, f);
	}

	public Vector3f(float x, float y, float z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public Vector3f(double x, double y, double z) {
		this((float)x, (float)y, (float)z);
	}

	public float getX() {
		return x;
	}

	public float getY() {
		return y;
	}

	public float getZ() {
		return z;
	}

	public boolean isNull() {
		return x==0 && y==0 && z==0;
	}

	public float length() {
		// returns the length, square root of (x²+y²+z²)
		return VectorUtil.length(this);
	}

	public Vector3f normalize() {
		float l = length();
		return l == 0 ? this
					  : new Vector3f(this.x / l, this.y / l, this.z / l);
	}

	public Vector3f multiply(double f) {
		return f==0 ? new Vector3f()
					: new Vector3f(x * f, y * f, z * f);
	}

	public Vector3f multiply(Vector3f v) {
		return new Vector3f(x==0 || v.x==0 ? 0 : x * v.x,
							y==0 || v.y==0 ? 0 : y * v.y,
							z==0 || v.z==0 ? 0 : z * v.z);
	}

	public Vector3f divide(double f) {
		if (f == 0)
			throw new IllegalArgumentException("division by zero: " + f);
		return new Vector3f(x / f, y / f, z / f);
	}

	public Vector3f divide(Vector3f v) {
		if (v.x==0 || v.y==0 || v.z==0)
			throw new IllegalArgumentException("division by zero: " + v);
		return new Vector3f(x / v.x, y / v.y, z / v.z);
	}

	public Vector3f crossProduct(Vector3f v) {
		float yz = y==0 || v.z==0 ? 0 : y * v.z,
			  zy = z==0 || v.y==0 ? 0 : z * v.y,
			  zx = z==0 || v.x==0 ? 0 : z * v.x,
			  xz = x==0 || v.z==0 ? 0 : x * v.z,
			  xy = x==0 || v.y==0 ? 0 : x * v.y,
			  yx = y==0 || v.x==0 ? 0 : y * v.x;
		return new Vector3f(yz - zy, zx - xz, xy - yx);
	}

	public float scalar(Vector3f v) {
		return VectorUtil.scalar(this, v);
	}

	public Vector3f add(Vector3f v) {
		return new Vector3f(x + v.x, y + v.y, z + v.z);
	}

	public Vector3f add(float x, float y, float z) {
		return new Vector3f(this.x + x, this.y + y, this.z + z);
	}

	public Vector3f add(float a) {
		return new Vector3f(x + a, y + a, z + a);
	}

	public Vector3f sub(Vector3f v) {
		return new Vector3f(x - v.x, y - v.y, z - v.z);
	}

	public Vector3f sub(float a) {
		return new Vector3f(x - a, y - a, z - a);
	}

	public Vector3f negate() {
		return new Vector3f(x==0 ? 0 : x * -1,
							y==0 ? 0 : y * -1,
							z==0 ? 0 : z * -1);
	}

	@Override
	public boolean equals(Object o) {
		if (o.getClass()!=getClass())
			return false;
		Vector3f v = (Vector3f)o;
		return x==v.x && y==v.y && z==v.z;
	}

	@Override
	public int hashCode() {
		int hash = 7;
		hash = 17 * hash + Float.floatToIntBits(this.x);
		hash = 17 * hash + Float.floatToIntBits(this.y);
		hash = 17 * hash + Float.floatToIntBits(this.z);
		return hash;
	}

	@Override
	public String toString() {
		return String.format("[%.1f, %.1f, %.1f]", x, y, z);
	}

}
